package models

import (
	"chat/log"
	"chat/utils"
	"encoding/json"
	"fmt"
	"net"
	"net/http"
	"strconv"
	"sync"
	"time"

	"github.com/dgrijalva/jwt-go"
	"github.com/gorilla/websocket"
	"gopkg.in/fatih/set.v0"
	"gorm.io/gorm"
)

// 消息
type Message struct {
	gorm.Model
	FormId       int64  `json:"form_id"  gorm:"消息发送者ID"`
	FormName     string `json:"form_name" gorm:"消息发送者名称"`
	FormAvatar   string `json:"form_avatar" gorm:"消息发送者头像"`
	TargetId     int64  `json:"target_id" gorm:"消息接收者ID"`
	TargetName   string `json:"target_name" gorm:"消息接收者名称"`
	TargetAvatar string `json:"target_avatar" gorm:"消息接收者头像"`

	// 1: 私聊 2: 群聊 3:广播 4：语音聊天和视频通话视频聊天
	Type int `json:"type" gorm:"消息类型"`

	// 1:文字 2:表情包 3:图片 4:文件 5:音频 6:发起通话  7：发送RTC相关数据包  8：挂断
	Media    int       `json:"media" gorm:"媒体类型"`
	Content  string    `json:"content" gorm:"消息内容"`
	Url      string    `json:"url" gorm:"文件地址"`
	Size     string    `json:"size" gorm:"文件大小"`
	Desc     string    `json:"desc" gorm:"消息描述"`
	Amount   int       `json:"amount" ` //gorm:"消息时长"`
	SendTime time.Time `json:"send_time" gorm:"发送时间"`
	Read     bool      `json:"read" gorm:"是否已读"`
	Duration string    `json:"duration"  gorm:"持续时间"`

	//以下数据保证数据完整性，因后面加的，修改代码太麻烦了，只增加代码
	RTCType   string `json:"rtc_type" gorm:"前端发送的WebRtc type"`
	SDP       string `json:"sdp" gorm:"双发交换的SDP数据"`
	Candidate string `json:"candidate" gorm:"双发交换的candidate数据"`
}

func (table *Message) TableName() string {
	return "message_basic"
}

func UpdateReadStatus(formID string, targetID string) error {
	if err := utils.Mysql.Model(&Message{}).Where("(form_id = ? AND target_id = ?) or (form_id = ? AND target_id = ?)", formID, targetID, targetID, formID).Update("read", true).Error; err != nil {
		return err
	}
	if err := utils.Mysql.Model(&Message{}).Where(" target_id = ? and type = 2", targetID).Update("read", true).Error; err != nil {
		return err
	}
	return nil
}

func FindFriendChatHistory(form string, target string) ([]*Message, error) {
	historys := make([]*Message, 0)
	if err := utils.Mysql.Where("((form_id = ? and target_id = ?) OR (target_id = ? and form_id  = ?)) AND type =1 OR (((type = 4 OR type = 5) AND amount > 1))", form, target, form, target).Find(&historys).Error; err != nil {
		return nil, err
	}
	return historys, nil
}

func FindGroupChatHistory(id string) ([]*Message, error) {
	historys := make([]*Message, 0)
	if err := utils.Mysql.Where("target_id = ? AND type = 2", id).Find(&historys).Error; err != nil {
		return nil, err
	}
	return historys, nil
}

func GetLastHistory(formID string, targetID string, action string) (Message, error) {
	var lastHistory Message
	if err := utils.Mysql.Where("((form_id = ? and target_id = ?) OR (target_id = ? and form_id  = ?))AND type = ?", formID, targetID, formID, targetID, action).Order("send_time desc").First(&lastHistory).Error; err != nil {
		return Message{}, err
	}
	return lastHistory, nil
}

func GetHistoryUserNotRead(formID string, targetID string, length *int) error {
	messages := make([]*Message, 0)
	err := utils.Mysql.Where("form_id = ? and target_id = ?  and `read` = 0 and type = 1", targetID, formID).Find(&messages).Error
	*length = len(messages)
	return err
}
func GetHistoryGroupNotRead(id string, length *int) error {
	messages := make([]*Message, 0)
	err := utils.Mysql.Where("target_id = ?  and `read` = 0 and type = 2", id).Find(&messages).Error
	*length = len(messages)
	return err
}

func createMessage(msg *Message) error {
	return utils.Mysql.Table("message_basic").Create(&msg).Error
}

// TODO: 聊天实现
type Node struct {
	Conn      *websocket.Conn
	DataQueue chan []byte
	GroupSets set.Interface
}

// 映射关系
var clientMap map[int64]*Node = make(map[int64]*Node, 0)

// 读写锁
var rwLocker sync.RWMutex

func Chat(w http.ResponseWriter, r *http.Request) {
	//检验token
	query := r.URL.Query()
	tokenString := query.Get("token")
	token, _ := jwt.ParseWithClaims(tokenString, &utils.Claims{}, func(token *jwt.Token) (interface{}, error) {
		return utils.JwtSecret, nil
	})
	_, ok := token.Claims.(*utils.Claims)
	userId, _ := strconv.ParseInt(query.Get("userId"), 10, 64)
	rwLocker.RLock()
	i, flag := clientMap[int64(userId)]
	rwLocker.RUnlock()
	if flag { //如果创建失败
		utils.RemoveOfflineUser(uint(userId))
		delete(clientMap, int64(userId))
		i.Conn.Close() // 关闭 WebSocket 连接
	}
	utils.SaveOnLineUser(uint(userId))
	var upgrader = websocket.Upgrader{
		CheckOrigin: func(r *http.Request) bool {
			return ok && token.Valid
		},
	}
	conn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Error(fmt.Sprintf("%v", err))
		return
	}
	node := &Node{
		Conn:      conn,
		DataQueue: make(chan []byte, 50),
		GroupSets: set.New(set.ThreadSafe),
	}
	rwLocker.Lock()
	clientMap[userId] = node
	rwLocker.Unlock()
	go sendProc(node)
	go recvProc(node)
}

func sendProc(node *Node) {
	for {
		select {
		case data := <-node.DataQueue:
			err := node.Conn.WriteMessage(websocket.TextMessage, data)
			if err != nil {
				log.Error(fmt.Sprintf("%v", err))
				return
			}
		}
	}
}

func recvProc(node *Node) {
	defer func() {
		node.Conn.Close()
	}()
	for {
		_, data, err := node.Conn.ReadMessage()
		if err != nil {
			log.Error(fmt.Sprintf("%v", err))
			break
		}
		msg := Message{}
		if err := json.Unmarshal(data, &msg); err != nil {
			log.Error(fmt.Sprintf("Error decoding message: %v", err))
			continue
		}
		if msg.Type == 100 {
			utils.RemoveOfflineUser(msg.ID)
			delete(clientMap, int64(msg.ID))
			node.Conn.Close() // 关闭 WebSocket 连接
			fmt.Printf("%v\n", clientMap)
			return
		}
		broadMsg(data)
		utils.Error(err)
	}
}

// 创建UDP数据存储链
var udpSendChan chan []byte = make(chan []byte, 1024)

// 将数据写入到udp链中
func broadMsg(data []byte) {
	udpSendChan <- data
}

// 启动程序会启动UDP发送、接收协程
func init() {
	go udpSendProc()
	go udpRecvProc()
}

// 完成UDP数据发送协程
func udpSendProc() {
	con, err := net.DialUDP("udp", nil, &net.UDPAddr{
		IP:   net.IPv4(127, 0, 0, 1),
		Port: 3000,
	})
	defer con.Close()
	utils.Error(err)
	for {
		select {
		case data := <-udpSendChan:
			_, err := con.Write(data)
			if err != nil {
				log.Error(fmt.Sprintf("%v", err))
				return
			}
		}
	}
}

// 完成UDP数据接收协程
func udpRecvProc() {
	log.Info("UDP recv procedure started ...")
	con, err := net.ListenUDP("udp", &net.UDPAddr{
		IP:   net.IPv4zero,
		Port: 3000,
	})
	utils.Error(err)
	defer con.Close()
	for {
		var buf [512]byte
		n, err := con.Read(buf[0:])
		if err != nil {
			log.Error(fmt.Sprintf("%v", err))
			return
		}
		dispatch(buf[0:n])
	}
}

// 后端调度逻辑
func dispatch(data []byte) {
	var msg Message
	err := json.Unmarshal(data, &msg)
	if err != nil {
		log.Error(fmt.Sprintf("%v", err))
		return
	}
	switch msg.Type {
	case 1:
		createMessage(&msg)
		sendMsg(msg.TargetId, data)
	case 2:
		createMessage(&msg)
		users, _ := FindGroupUsers(uint(msg.TargetId))
		sendGroupMsg(data, users, msg.FormId)
	case 4:
		Call(msg, data)
	case 6:
		connection()
	}
}

func connection() {

}

func sendMsg(id int64, msg []byte) {
	rwLocker.RLock()
	node, ok := clientMap[id]
	rwLocker.RUnlock()
	if ok {
		node.DataQueue <- msg
	}
}

func sendGroupMsg(msg []byte, users []*UserBasic, formid int64) {
	for _, user := range users {
		if formid != int64(user.ID) {
			rwLocker.RLock()
			i, ok := clientMap[int64(user.ID)]
			rwLocker.RUnlock()
			fmt.Printf("当前全成员在线的有%v", user.NickName)
			if ok {
				i.DataQueue <- msg
			}
		}
	}

}

func Call(msg Message, data []byte) {
	fmt.Printf("在线用户有%v\n", clientMap)
	rwLocker.RLock()
	to, ok := clientMap[int64(msg.TargetId)]
	rwLocker.RUnlock()
	if ok {
		if msg.Media == 10 {
			if err := createMessage(&msg); err != nil {
				fmt.Printf("创建消息出错")
			}
			var room RoomBasic
			room.Name = ""
			// CreateRoom()
		}
		to.DataQueue <- data
	} else {
		rwLocker.RLock()
		i, ok := clientMap[int64(msg.FormId)]
		rwLocker.RUnlock()
		if ok {
			i.DataQueue <- data
		}
	}

	// switch msg.Content {
	// case "calling":
	// 	err := utils.Mysql.Table("message_vasic").Where("id = ?", msg.ID).Update("amount", 0).Error
	// case "called":

	// case "":

	// }

}
